
// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include <zencore/memory.h>
#include <zencore/zencore.h>

#include <memory>
#include <optional>

namespace zen {

template<size_t BitCount>
struct CryptoBits
{
public:
	static constexpr size_t ByteCount = BitCount / 8;

	CryptoBits() = default;

	bool IsNull() const { return memcmp(&m_Bits, &Zero, ByteCount) == 0; }
	bool IsValid() const { return IsNull() == false; }

	size_t GetSize() const { return ByteCount; }
	size_t GetBitCount() const { return BitCount; }

	MemoryView GetView() const { return MemoryView(m_Bits, ByteCount); }

	static CryptoBits FromMemoryView(MemoryView Bits)
	{
		if (Bits.GetSize() != ByteCount)
		{
			return CryptoBits();
		}

		return CryptoBits(Bits);
	}

	static CryptoBits FromString(std::string_view Str) { return FromMemoryView(MakeMemoryView(Str)); }

private:
	CryptoBits(MemoryView Bits)
	{
		ZEN_ASSERT(Bits.GetSize() == GetSize());
		memcpy(&m_Bits, Bits.GetData(), GetSize());
	}

	static constexpr uint8_t Zero[ByteCount] = {0};

	uint8_t m_Bits[ByteCount] = {0};
};

using AesKey256Bit = CryptoBits<256>;
using AesIV128Bit  = CryptoBits<128>;

class Aes
{
public:
	static constexpr size_t BlockSize = 16;

	static MemoryView Encrypt(const AesKey256Bit&		  Key,
							  const AesIV128Bit&		  IV,
							  MemoryView				  In,
							  MutableMemoryView			  Out,
							  std::optional<std::string>& Reason);

	static MemoryView Decrypt(const AesKey256Bit&		  Key,
							  const AesIV128Bit&		  IV,
							  MemoryView				  In,
							  MutableMemoryView			  Out,
							  std::optional<std::string>& Reason);
};

void crypto_forcelink();

}  // namespace zen
